package cn.broadsense.biz.service.impl;

import cn.broadsense.biz.bo.channel.ChannelOrgBo;
import cn.broadsense.biz.bo.channel.ChannelTagBo;
import cn.broadsense.biz.convert.ChannelConvert;
import cn.broadsense.biz.domain.*;
import cn.broadsense.biz.dto.Channel3dDataDto;
import cn.broadsense.biz.dto.ChannelOrgCountDto;
import cn.broadsense.biz.dto.ChannelOrgTreeDto;
import cn.broadsense.biz.mapper.ChannelMapper;
import cn.broadsense.biz.mapper.ChannelOrgMapper;
import cn.broadsense.biz.service.*;
import cn.broadsense.biz.vo.ChannelVo;
import cn.broadsense.biz.vo.SearchChannelVo;
import cn.broadsense.common.annotation.DataScope;
import cn.broadsense.common.exception.ServiceException;
import cn.broadsense.common.utils.PageUtils;
import cn.broadsense.common.utils.SecurityUtils;
import cn.broadsense.common.utils.bean.BeanUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author pengxin
 * @description 针对表【t_channel(点位表 )】的数据库操作Service实现
 * @createDate 2023-09-12 10:55:35
 */
@Service
public class ChannelServiceImpl extends ServiceImpl<ChannelMapper, Channel>
        implements ChannelService {


    @Resource
    private Channel3dDataService channel3dDataService;

    @Resource
    private ChannelMapper channelMapper;

    @Resource
    private ChannelOrgMapper channelOrgMapper;

    @Resource
    private ChannelFollowService channelFollowService;

    @Resource
    private ChannelTagDetailsService channelTagDetailsService;

    @Resource
    private ChannelTagService channelTagService;

    @Resource
    private ChannelConvert channelConvert;

    @Autowired
    private ChannelOrgService channelOrgService;


    @Override
    @DataScope(deptAlias = "t")
    public List<Channel> findPage(Channel channel) {
        if (channel.getIsPage()) {
            PageUtils.startPage();
        }
        channel.setUserId(SecurityUtils.getUserId());
        return channelMapper.findList(channel);
    }

    @DataScope(deptAlias = "t")
    @Override
    public List<Channel> findPageV2(Channel channel) {
        PageUtils.startPage();
        channel.setUserId(SecurityUtils.getUserId());
        List<Channel> listV2 = channelMapper.findListV2(channel);
        if (CollUtil.isNotEmpty(listV2)) {
            List<Long> channelIds = listV2.stream().map(Channel::getId).collect(Collectors.toList());
            List<ChannelTag> channelTagList = channelTagService.listByChannelIds(channelIds);
            if (CollUtil.isNotEmpty(channelTagList)) {
                Map<Long, List<ChannelTag>> channelTagMap = channelTagList.stream().collect(Collectors.groupingBy(ChannelTag::getChannelId));
                listV2.forEach(e -> e.setChannelTagList(channelTagMap.get(e.getId())));
            }
        }
        return listV2;
    }

    @Override
    public List<Channel> queryOrgChannels(ChannelOrgBo bo) {
        List<String> orgCodes = bo.getOrgCodes();
        List<ChannelOrg> orgs = new ArrayList<>();
        if (orgCodes != null && orgCodes.size() > 0) {
            orgCodes.stream().forEach(orgCode -> {
                LambdaQueryWrapper<ChannelOrg> query = new LambdaQueryWrapper<>();
                query.like(ChannelOrg::getFullOrgCode, orgCode);
                List<ChannelOrg> list = channelOrgService.list(query);
                orgs.addAll(list);
            });
            orgCodes = orgs.stream().map(a -> a.getOrgCode()).collect(Collectors.toList());
        }
        bo.setOrgCodes(orgCodes);
        bo.setUserId(1);
        return channelMapper.queryOrgChannels(bo);
    }

    @Override
    public List<Channel> queryTagChannels(ChannelTagBo bo) {
        List<Long> codes = bo.getTagIds();
        if (codes != null && codes.size() > 0) {
            List<Long> queryCodes = this.queryChannelTagCodes(codes, codes);
            bo.setTagIds(queryCodes);
        }
        bo.setUserId(1);
        return channelMapper.queryTagChannels(bo);
    }

    private List<Long> queryChannelTagCodes(List<Long> mainCodes, List<Long> codes) {
        List<String> tagCodes = channelTagService.listByIds(codes).stream().map(tag -> tag.getCode()).collect(Collectors.toList());
        if (tagCodes != null && tagCodes.size() > 0) {
            List<ChannelTag> tags = channelTagService.list(new LambdaQueryWrapper<ChannelTag>().in(ChannelTag::getParentCode, tagCodes));
            if (tags != null && tags.size() > 0) {
                List<Long> queryCodes = tags.stream().map(tag -> tag.getId()).collect(Collectors.toList());
                mainCodes.addAll(queryCodes);
                this.queryChannelTagCodes(mainCodes, queryCodes);
            }
        }
        return mainCodes;
    }


    @Override
    public Channel getDetails(Long id) {
        Channel details = this.getById(id);
        if (details != null) {
            Channel3dData channel3dData = channel3dDataService.getByChannelId(id);
            if (channel3dData != null) {
                Channel3dDataDto dto = new Channel3dDataDto();
                BeanUtils.copyBeanProp(dto, channel3dData);
                details.setChannel3dData(dto);
            }
            List<ChannelTagDetails> tagDetails = channelTagDetailsService.listByChannelId(id);

            if (CollUtil.isNotEmpty(tagDetails)) {
                List<ChannelTagDetails> customTagList = new ArrayList<>();
                Set<Long> collect = new HashSet<>();
                for (ChannelTagDetails tagDetail : tagDetails){
                    if(tagDetail.getTagId() != null && tagDetail.getTagType() == 1){
                        collect.add(tagDetail.getTagId());
                    }else if( tagDetail.getTagType() == 2){
                        customTagList.add(tagDetail);
                    }
                }

                details.setTagList(CollUtil.newArrayList(collect));
                if(CollUtil.isNotEmpty(collect)){
                    details.setChannelTagList(channelTagService.listByIds(details.getTagList()));
                }
                details.setCustomTagList(customTagList);
            }
        }
        return details;
    }

    @Override
    public List<ChannelOrg> channelOrgByParentCode(String parentCode) {
        LambdaQueryWrapper<ChannelOrg> query = new LambdaQueryWrapper<>();
        query.eq(ChannelOrg::getParentOrgCode, parentCode);
        return channelOrgMapper.selectList(query);
    }

    @Override
    public void followChannel(Long id, Integer type) {
        Long userId = SecurityUtils.getUserId();
        LambdaQueryWrapper<ChannelFollow> query = new LambdaQueryWrapper<>();
        query.eq(ChannelFollow::getUserId, userId);
        query.eq(ChannelFollow::getChannelId, id);
        query.eq(ChannelFollow::getType, 1);
        ChannelFollow channelFollow = channelFollowService.getOne(query);
        //收藏点位
        if (type == 1) {
            if (channelFollow != null) {
                throw new ServiceException("该点位已收藏请勿重复操作");
            }
            ChannelFollow addFollow = new ChannelFollow();
            addFollow.setChannelId(id);
            addFollow.setType(1);
            addFollow.setUserId(userId);
            channelFollowService.save(addFollow);
        }
        //取消收藏
        else {
            if (channelFollow == null) {
                throw new ServiceException("该点位未收藏");
            }
            channelFollowService.removeById(channelFollow.getId());
        }
    }

    @Override
    public List<ChannelOrgCountDto> countByOrgQty() {
        return channelMapper.countByOrgQty();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(Long id, ChannelVo channelVo) {
        if (channelVo == null) {
            return;
        }
        Channel channel = channelConvert.toChannel(channelVo);
        channel.setId(id);


        //更新3维数据
        if (channelVo.getChannel3dData() != null ) {

            //查询是否有3维数据
            Channel3dData one = channel3dDataService.getOne(new LambdaQueryWrapper<Channel3dData>().eq(Channel3dData::getChannelId, id)

                    .orderByDesc(Channel3dData::getId).last("limit 1"));
            if(one != null){
                channelVo.getChannel3dData().setId(one.getId());
                channel3dDataService.updateById(channelVo.getChannel3dData());
            }else{
               // 是否全部字段都为空
                if(isAllFieldsNull(channelVo.getChannel3dData())) {
                    return;
                }
                channelVo.getChannel3dData().setChannelId(id);
                channelVo.getChannel3dData().setChannelName(channel.getChannelName());
                channel3dDataService.save(channelVo.getChannel3dData());
            }
            channel.setThreeDDataStatus(2);
        }
        this.updateById(channel);
    }

    public static boolean isAllFieldsNull(Channel3dData data) {
        if (data == null) {
            return true;
        }

        Field[] fields = Channel3dData.class.getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            try {
                Object value = field.get(data);
                if (value != null) {
                    if (value instanceof String && !((String) value).trim().isEmpty()) {
                        return false;
                    } else if (value instanceof Collection && !((Collection<?>) value).isEmpty()) {
                        return false;
                    } else if (value instanceof Map && !((Map<?, ?>) value).isEmpty()) {
                        return false;
                    } else if (value instanceof Boolean && ((Boolean) value)) {
                        return false;
                    } else if (value instanceof Number && ((Number) value).doubleValue() != 0.0) {
                        return false;
                    } else if (value instanceof Character && ((Character) value) != '\0') {
                        return false;
                    }
                }
            } catch (IllegalAccessException e) {
                return true;
            }
        }
        return true;
    }

    @Override
    public void importData(List<ChannelVo> list) {
        if (CollUtil.isNotEmpty(list)) {
            List<Channel> channelList = new ArrayList<>();
            list.forEach(e -> {
                Channel channel = channelConvert.toChannel(e);
                channel.setId(IdUtil.getSnowflakeNextId());
                channel.setChannelSn(e.getChannelCode());
                channel.setDataSource(2);
                channelList.add(channel);
            });
            this.saveBatch(channelList);
        }
    }

    @Override
    public List<Channel> searchChannelList(SearchChannelVo searchChannelVo) {
        return this.channelMapper.searchChannelList(searchChannelVo);
    }

    @Override
    public List<Channel> polygonChannel(List<String> coordinateList) {
        String polygonWkt = buildPolygonWkt(coordinateList);
        return channelMapper.polygonChannel(polygonWkt);
    }

    @DataScope(deptAlias = "t")
    @Override
    public List<Channel> getList(Channel channel) {
        channel.setUserId(SecurityUtils.getUserId());
        return channelMapper.getList(channel);
    }

    @Override
    public void addCustomTag(Long channelId, String customTag) {
        ChannelTagDetails tagDetails = new ChannelTagDetails();
        tagDetails.setChannelId(channelId);
        tagDetails.setTagType(2);
        tagDetails.setCreateTime(new Date());
        tagDetails.setTagId(IdUtil.getSnowflakeNextId());
        tagDetails.setTagName(customTag);
        channelTagDetailsService.save(tagDetails);
    }

    @Override
    public void editCustomTag(Long id, String customTag) {
        ChannelTagDetails tagDetails = new ChannelTagDetails();
        tagDetails.setId(id);
        tagDetails.setTagType(2);
        tagDetails.setTagName(customTag);
        channelTagDetailsService.updateById(tagDetails);
    }

    @Override
    public void delCustomTag(Long id) {
        channelTagDetailsService.removeById(id);
    }

    private String buildPolygonWkt(List<String> coordinateList) {
        // 确保多边形是闭合的
        if (!coordinateList.get(0).equals(coordinateList.get(coordinateList.size() - 1))) {
            coordinateList.add(coordinateList.get(0));
        }
        List<String> coordinateList1 = new ArrayList<>();
        for (String coordinate : coordinateList) {
            coordinateList1.add(StrUtil.replace(coordinate, ",", " "));
        }
        // 构建多边形 WKT 字符串
        String coordinates = String.join(", ", coordinateList1);
        return "POLYGON((" + coordinates + "))";
    }
}




